package com.shell;

import com.cmd.FileModel;
import com.util.Config;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.PropertySource;
import org.springframework.util.DigestUtils;

import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@PropertySource({"file:${user.dir}/config/nettyserver.properties"})

//@PropertySource({"file:${user.dir}/config/nettyserverzhprod.properties"})


@ComponentScan(basePackages = {"com"})
@SpringBootApplication
public class Update implements CommandLineRunner {

    public static void main(String[] args) throws Exception {
        SpringApplication.run(Update.class, args);
    }

    public void run(String... args) throws Exception {

        updateEnabled();
    }

    public static String dateStr = null;

    static {
        File dirFile = new File(Config.config.getProperty("local.url"));
        File[] files = dirFile.listFiles();
        for (File file : files) {
            System.err.println(file.getName());
            dateStr = file.getName();
            break;
        }
    }


    /**
     * 开始更新
     */
    public void updateEnabled() throws Exception {
        String update = Config.config.getProperty("enabled");
        String[] strs = update.split(",");
        for (String str : strs) {
            long start = System.currentTimeMillis();
            System.err.println();
            System.err.println();
            System.err.println("----------------------------------  开始更新 " + str + " 环境.......");
            switch (str) {
                case "test":
                    String test_ip = Config.config.getProperty("test.ip");
                    int test_port = Integer.parseInt(Config.config.getProperty("test.port"));
                    String test_username = Config.config.getProperty("test.username");
                    String test_password = Config.config.getProperty("test.password");
                    updateServer(test_ip, test_port, test_username, test_password, str);
                    break;
                case "uat":
                    String uat_ip = Config.config.getProperty("uat.ip");
                    int uat_port = Integer.parseInt(Config.config.getProperty("uat.port"));
                    String uat_username = Config.config.getProperty("uat.username");
                    String uat_password = Config.config.getProperty("uat.password");
                    updateServer(uat_ip, uat_port, uat_username, uat_password, str);
                    break;
                case "prod":
                    String prod_ip = Config.config.getProperty("prod.ip");
                    int prod_port = Integer.parseInt(Config.config.getProperty("prod.port"));
                    String prod_username = Config.config.getProperty("prod.username");
                    String prod_password = Config.config.getProperty("prod.password");
                    updateServer(prod_ip, prod_port, prod_username, prod_password, str);
                    break;
            }
            System.err.println("----------------------------------  结束更新 " + str + " 环境....... 耗时：" + (System.currentTimeMillis() - start));
        }
    }

    // todo
    public void updateServer(String ip, int port, String username, String password, String enabled) throws Exception {
        // 开始更新jar包
        String update = Config.config.getProperty("server");
        String[] strs = update.split(",");
        for (String str : strs) {
            long start = System.currentTimeMillis();
            System.err.println("开始更新 " + str + " 服务器.......");
            switch (str) {
                case "web":
                    updateJar(ip, port, username, password, "web-server");
                    updateConfig(ip, port, username, password, "web-server");
                    execShell(ip, port, username, password, "web-server", enabled);
                    break;
                case "center":
                    updateJar(ip, port, username, password, "center-server");
                    updateConfig(ip, port, username, password, "center-server");
                    execShell(ip, port, username, password, "center-server", enabled);
                    break;
                case "game":
                    updateJar(ip, port, username, password, "game-server");
                    updateConfig(ip, port, username, password, "game-server");
                    execShell(ip, port, username, password, "game-server", enabled);
                    break;
                case "global":
                    updateJar(ip, port, username, password, "global-server");
                    updateConfig(ip, port, username, password, "global-server");
                    execShell(ip, port, username, password, "global-server", enabled);
                    break;
                case "admin":
                    updateJar(ip, port, username, password, "admin-server");
                    updateConfig(ip, port, username, password, "admin-server");
                    execShell(ip, port, username, password, "admin-server", enabled);
                    break;
            }
            System.err.println("结束更新 " + str + " 服务器....... 耗时：" + (System.currentTimeMillis() - start));
            System.err.println();
        }
    }

    // 上传jar
    public synchronized void updateJar(String ip, int port, String username, String password, String server) {
        boolean jar = Boolean.parseBoolean(Config.config.getProperty("update.jar"));
        if (!jar){
            System.err.println("------------------------ 不需要更新jar包 "+server+" ----------------------------");
            return;
        }
        ScpClientUtil scpClient = ScpClientUtil.getInstance(ip, port, username, password);
        // /data/innohive/portal/ip005/web-server/libs/
        String remote = Config.config.getProperty("remote.url") + server + "/libs/";

        // 本地jar地址 I:\\project\\IP005\\publish\\2024-07-29\\web-server\\libs\\litchi.jar
        String local_litchi = Config.config.getProperty("local.url") + dateStr + "\\" + server + "\\libs\\litchi.jar";
        scpClient.putFile(local_litchi, remote);
        System.out.println("上传jar完毕:" + local_litchi);
        String local_shared = Config.config.getProperty("local.url") + dateStr + "\\" + server + "\\libs\\game-shared.jar";
        scpClient.putFile(local_shared, remote);
        System.out.println("上传jar完毕:" + local_shared);
        String local_protocol = Config.config.getProperty("local.url") + dateStr + "\\" + server + "\\libs\\protocol.jar";
        scpClient.putFile(local_protocol, remote);
        System.out.println("上传jar完毕:" + local_protocol);

        // 更新服务器包 web-server center-server game-server admin-server
        String local_jar = Config.config.getProperty("local.url") + dateStr + "\\" + server + "\\libs\\" + server + ".jar";
        scpClient.putFile(local_jar, remote);
        System.out.println("上传jar完毕:" + local_jar);
    }

    // 上传config
    public synchronized void updateConfig(String ip, int port, String username, String password, String server) throws IOException {

        boolean configs = Boolean.parseBoolean(Config.config.getProperty("update.configs"));
        if (!configs){
            System.err.println("------------------------ 不需要更新configs表 "+server+" ----------------------------");
            return;
        }

        ScpClientUtil scpClient = ScpClientUtil.getInstance(ip, port, username, password);

        String remote_config = Config.config.getProperty("remote.url") + server + "/config/";
        String remote_configMd5 = Config.config.getProperty("remote.url") + server + "/config/configMd5.txt"; // /data/innohive/portal/ip005/
        String remote_dataconfig = Config.config.getProperty("remote.url") + server + "/config/dataconfig"; // /data/innohive/portal/ip005/
        String local = Config.config.getProperty("local.url") + dateStr + "\\" + server + "\\config\\"; // I:\\project\\IP005\\publish\\2024-07-30\\admin-server

        // 源文件地址
        Map<String, FileModel> sourceMap = getFiles(local + "dataconfig");
        // 从远程服务器/opt下的index.html下载到本地项目根路径下
        scpClient.getFile(remote_configMd5, local);
        // 远程的config的md5 key:文件名  value ：md5
        Map<String, String> stringMap = redTxt(local + "configMd5.txt"); //  I:\\project\\IP005\\publish\\2024-07-30\\admin-server I:\project\IP005\protocol\proto\proto.txt

        StringBuffer stringBuffer = new StringBuffer();
        int count = 0;
        // 本地config文件 和远程config文件 做md5比较
        for (Map.Entry<String, FileModel> entry : sourceMap.entrySet()) {
            FileModel fileModel = entry.getValue();
            stringBuffer.append(fileModel.file.getName()).append(":").append((entry.getValue()).getMd5()).append("\n");
            String md5 = stringMap.get(fileModel.getFile().getName());
            if (md5 != null && md5.equals(fileModel.md5)) {
                continue;
            }
            count++;
            scpClient.putFile(entry.getKey(), remote_dataconfig);
            System.out.println("---更新配置表：" + fileModel.getFile().getName());
        }

        writeTxt(local + "configMd5.txt", stringBuffer.toString());
        // 把本地目录下的文件 上传到服务器上
        scpClient.putFile(local + "configMd5.txt", remote_config);
        if (count > 0) {
            System.out.println("配置表更新完毕 .....");
        } else {
            System.out.println("配置表无变化 不需要更新.....");
        }
    }

    // 执行脚本
    public void execShell(String ip, int port, String username, String password, String server, String enabled) {
        boolean execute = Boolean.parseBoolean(Config.config.getProperty("execute"));
        //  如果是正式环境 是否需要执行shell关闭的话 那么就直接返回
//        if (enabled.equals("prod")){
//            if (!execute){
//                System.err.println("------------------------ 正式服 执行shell脚本开关 关闭 ----------------------------");
//                return;
//            }
//        }
//        if (!execute){
//            System.err.println("------------------------  执行shell脚本开关 关闭 "+server+" ----------------------------");
//            return;
//        }
        // todo 执行命令
        SshUtil execut = new SshUtil(ip, username, password, port);
        String sh_url = "cd /data/innohive/portal/ip005/" + server;
        // 获取服务器状态
        StringBuffer sb0 = new StringBuffer();
        String status = "sh " + server + ".sh status";
        sb0.append(sh_url).append("\n").append(status);
        String result0 = execut.executeForResult(sb0.toString());
        // 如果是正在运行 则restart
        if (result0.contains("is running")) {
            StringBuffer sb1 = new StringBuffer();
            String restart = "sh " + server + ".sh restart";
            sb1.append(sh_url).append("\n").append(restart);
            String result1 = execut.executeForResult(sb1.toString());
            System.out.println("重启成功.....");
            // 不在运行 则启动 start
        } else {
            StringBuffer sb2 = new StringBuffer();
            String start = "sh " + server + ".sh start";
            sb2.append(sh_url).append("\n").append(start);
            String result2 = execut.executeForResult(sb2.toString());
            System.out.println("启动成功.....");
        }
        execut.close();
    }

    public static Map<String, String> redTxt(String path) {
        StringBuilder result = new StringBuilder();
        Map<String, String> maps = new HashMap();
        File file = new File(path);
        try {
            BufferedReader br = new BufferedReader(new FileReader(file));
            String s = null;
            while ((s = br.readLine()) != null) {
                String str = System.lineSeparator() + s;
                result.append(str);
                if (str != null) {
                    Pattern p = Pattern.compile("\\s*|\\t|\\r|\\n");
                    Matcher m = p.matcher(str);
                    str = m.replaceAll("");
                }
                String[] arr = str.split(":");
                if (arr.length == 2) {
                    maps.put(arr[0], arr[1]);
                }
            }
            br.close();
        } catch (Exception var9) {
            var9.printStackTrace();
        }
        return maps;
    }

    private static Map<String, FileModel> getFiles(String path) throws IOException {
        Map<String, FileModel> map = new HashMap();
        File folder = new File(path);
        Object[] files = getFileList(folder).toArray();
        Arrays.sort(files);
        Object[] var4 = files;
        int var5 = files.length;
        for (int var6 = 0; var6 < var5; ++var6) {
            Object obj = var4[var6];
            File file = (File) obj;
            String key = file.getAbsolutePath().replaceAll("\\\\", "/");
            String md5 = "";
            if (file.isFile()) {
                md5 = DigestUtils.md5DigestAsHex(new FileInputStream(file));
            }
            FileModel fileModel = new FileModel(file, md5);
            map.put(key, fileModel);
        }
        return map;
    }

    private static List<File> getFileList(File folder) {
        List<File> list = new ArrayList();
        File[] files = folder.listFiles();
        File[] var3 = files;
        int var4 = files.length;

        for (int var5 = 0; var5 < var4; ++var5) {
            File file = var3[var5];
            list.add(file);
            if (file.isDirectory()) {
                List<File> fileList = getFileList(file);
                list.addAll(fileList);
            }
        }
        return list;
    }

    public static void writeTxt(String path, String context) {
        try {
            File file = new File(path);
            FileOutputStream fileOutputStream = null;
            if (!file.exists()) {
                file.createNewFile();
            }
            fileOutputStream = new FileOutputStream(file);
            fileOutputStream.write(context.getBytes("utf-8"));
            fileOutputStream.flush();
            fileOutputStream.close();
        } catch (Exception var4) {
            var4.printStackTrace();
        }
    }

    private static final SimpleDateFormat datetimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    public static final String getDataTimeFormatString(Date date) {
        if (date == null) {
            return "";
        }
        String key[] = datetimeFormat.format(date.getTime()).split(" ");
        return key[0];
    }

}
